Skip to content

usb: device_next: new USB Video Class (UVC) implementation #76798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 27, 2025

Conversation

josuah
Copy link
Collaborator

@josuah josuah commented Aug 7, 2024

@josuah
Copy link
Collaborator Author

josuah commented Aug 7, 2024

I am grateful for the work on the USB and Video stacks of Zephyr, as well as the entire Zephyr tree, on the shoulder of which this is built.

@josuah josuah added priority: low Low impact/importance bug area: USB Universal Serial Bus area: Video Video subsystem area: Devicetree Binding PR modifies or adds a Device Tree binding labels Aug 7, 2024
@josuah
Copy link
Collaborator Author

josuah commented Aug 8, 2024

Force push:

  • fixes to make it compile with west build -b frdm_mcxn947/mcxn947/cpu0 (a board I happened to have, open to suggestions)
  • added another commit (with I hope proper attributions!) to introduce fragments, which UVC and this implementation support.

@josuah
Copy link
Collaborator Author

josuah commented Aug 8, 2024

Force-push:

  • Add a sample to illustrate the usage. It is not yet tested but compiles.

Comment on lines 920 to 961
.dwMinBitRate = sys_cpu_to_le32(15360000), \
.dwMaxBitRate = sys_cpu_to_le32(15360000), \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are these values coming from?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are chosen arbitrarily, and I need to think about what should I do here: pick reasonable defaults? Deduce from other values? Let the user figure out by exposing a devicetree option?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In future work, it will be possible to ask the sensor for VIDEO_CID_PIXEL_RATE in combination with video_bits_per_pixel() to generate this field.

.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = 0x81, \
.bmAttributes = USB_EP_TYPE_BULK, \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe UVC can be BULK or ISO.... but I only see BULK supported here. Do you plan to have a way to select which type of EP?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to mention that only BULK is supported through this early version. I will need to spend more time investigating the device_next APIs for how ISO is implemented.

I cannot guarantee ETAs as I would do this feature on free time, but will add it to the roadmap: this will be needed at some point.

@josuah
Copy link
Collaborator Author

josuah commented Aug 8, 2024

Very grateful for your reviews @XenuIsWatching I will force-push with the changes as soon as I get a chance to do so.

@josuah
Copy link
Collaborator Author

josuah commented Aug 21, 2024

Force-push:

  • control a selected source = <&dev>; device from the UVC stack directly
  • wait that a format got selected before queuing video buffers to the USB
  • use "discrete" frame intervals (FPS) values, which seemed to help getting it to work under Windows
  • USB3CV compliant descriptors

@josuah josuah force-pushed the pr-usb-uvc branch 2 times, most recently from 182ac7c to cec26cc Compare August 21, 2024 11:43
@josuah josuah force-pushed the pr-usb-uvc branch 2 times, most recently from 02c1087 to 4bdc1ea Compare September 7, 2024 15:46
@josuah
Copy link
Collaborator Author

josuah commented Sep 7, 2024

force push: rebased on main

@josuah
Copy link
Collaborator Author

josuah commented Sep 7, 2024

force push: changed the way descriptors are declared and introduce video controls at the descriptor level (no support for controls commands yet)

@josuah josuah changed the title usb: device_next: new USB Video Class implementation usb: device_next: new USB Video Class (UVC) implementation Sep 12, 2024
@josuah
Copy link
Collaborator Author

josuah commented Sep 12, 2024

force push: implemented the UVC controls for the supported Video class controls.

I did not test this yet with the samples, but on the internal fork, we could get an IMX219 sensor with exposure and gain control from the host, format selection at startup (but not runtime, see [1]).

I believe that the last step for me is to test the sample on several boards that support device_next and fix the CI.

@josuah
Copy link
Collaborator Author

josuah commented Sep 12, 2024

Known limitations:

[1]: there is currently no <video.h> API to let the application know that a format change occurred. For now, the sample waits that the host makes an initial choice, and does not reconsider its format selection.
A trade-off between supported feature and sample complexity.

[2]: there is currently no <video.h> API to let the video device communicate their min/max/step, so 0 is always picked as min, INT32/16/8_MAX as max, and 1 as step. Maybe the solution is to define an unit for each of the controls and have every sensor map this to their local definition. For instance, 1 µs for exposure, 1/1000 for gain, etc, and have the max value implicit. DONE

[3]: The "default" value is an arbitrary value of 1 instead of querying the controls of each sensor. DONE

[4]: There is no device const struct uvc_conf and only struct uvc_data, which wastes precious memory. DONE.

[5]: There are missing implementations for selector unit, extensions unit, encoding unit. TODO.

[6]: UVC introduces dependencies between some controls, i.e. auto-expopsure needs to be off for exposure to be accepted. DONE (as part of Zephyr Video).

[7]: UVC has "error" control type reporting the last error. DONE

[8]: Only a single endpoint and output/streaming interface is supported per UVC interface. Composite devices (multiple UVC classes per device) are used instead for supporting multiple video streams per device. DONE

[9]: No documentation outside the devicetree bindings. DONE (no documentation needed anymore as no configuration required).

[10]: Supports custom header size, but not passing custom header data yet.

[11]: Still image capture (capturing one frame at full resolution) not supported.

[12]: USB3CV compliance tests not all passing. TODO.

[13]: Announcing different resolutions/FPS for different connection speed not supported.

[14]: Asynchronous controls (the host setting a control, and a notification interrupt alert of completion) not supported.

Supported features:

[A]: Class API and enumeration

[B]: Custom control chains descriptors built from the devicetree layout Not supported by Linux

[C]: Selection of which controls to expose to the host via devicetree toggles Now controlled by the drivers.

[D]: Per-control entity tuning Sending all the controls requests to the first driver of the pipeline.

[E]: Handling of control commands end-to-end from host to Zephyr video device

[F]: Zephyr native Video API that allows to enqueue/dequeue frames like any other Zephyr video device.

[G]: Supports fragmented frames as discussed in #66994 and #72827

[H]: Can configure pixel format and resolution on the devicetree Done automatically by asking the video drivers.

[I]: Supports querying the min/max/current values of every controls end-to-end from host to Zephyr video driver.

@josuah
Copy link
Collaborator Author

josuah commented Jun 26, 2025

I did not get USB/IP to work so far:

$ west build -b native_sim/native/64 --snippet "usbip-native-sim video-sw-generator" samples/subsys/usb/uvc/
$ west flash
-- west flash: rebuilding
[2/2] Running utility command for native_runner_executable
-- west flash: using runner native
WARNING: Using a test - not safe - entropy source
*** Booting Zephyr OS build v4.1.0-6399-g886a9562b656 ***
[00:00:00.000,000] <inf> net_config: Initializing network
[00:00:00.000,000] <inf> net_config: IPv4 address: 192.0.2.1
[00:00:00.000,000] <inf> uvc_sample: Waiting the host to select the video format
# usbip list -r 192.0.2.1
Exportable USB devices
======================
 - 192.0.2.1
        1-1: NordicSemiconductor : unknown product (2fe3:0011)
           : /sys/bus/usb/devices/usb1/1-1
           : Miscellaneous Device / ? / Interface Association (ef/02/01)
           :  0 - Video / Video Control / unknown protocol (0e/01/00)
           :  1 - Video / Video Streaming / unknown protocol (0e/02/00)
# usbip attach -r 192.0.2.1 -b 1-1
[00:00:22.601,001] <err> usbd_ch9: HWINFO not implemented or enabled
[00:00:22.651,001] <err> usbd_ch9: HWINFO not implemented or enabled
[00:00:22.701,001] <err> usbd_ch9: HWINFO not implemented or enabled
[00:00:22.751,001] <err> usbd_ch9: HWINFO not implemented or enabled
[00:00:22.801,001] <err> usbd_ch9: HWINFO not implemented or enabled
[00:00:22.851,001] <err> usbd_ch9: HWINFO not implemented or enabled

However, it could be detected on Linux to some extent:

# dmesg -c
[ 1078.039367] usb 3-1: New USB device found, idVendor=2fe3, idProduct=0011, bcdDevice= 4.01
[ 1078.039390] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1078.039398] usb 3-1: Product: UVC sample
[ 1078.039405] usb 3-1: Manufacturer: Zephyr Project
[ 1078.188671] uvcvideo 3-1:1.1: Unknown video format 33424752-0000-0010-8000-00aa00389b71
[ 1078.188689] uvcvideo 3-1:1.1: Unknown video format 34325842-0000-0010-8000-00aa00389b71
[ 1078.188715] usb 3-1: Found UVC 1.50 device UVC sample (2fe3:0011)
[ 1078.389396] uvcvideo 3-1:1.1: Failed to set UVC probe control : 0 (exp. 48).

@jfischer-no
Copy link
Collaborator

jfischer-no commented Jun 26, 2025

I did not get USB/IP to work so far:

I was too hasty, connected too many USB UVC devices to my host.

[ 1078.389396] uvcvideo 3-1:1.1: Failed to set UVC probe control : 0 (exp. 48).

I see it on my side too.

@josuah
Copy link
Collaborator Author

josuah commented Jun 26, 2025

Force-push:

  • CI fix due to missing cast between (uint8_t *) of buf->data and (struct uvc_probe *)'
  • Use 0-length buffers (correct behavior) instead of empty string "" providing a \0 (hackish).

jfischer-no
jfischer-no previously approved these changes Jun 26, 2025
Copy link
Collaborator

@jfischer-no jfischer-no left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kartben please review

CONFIG_LOG=y
CONFIG_POLL=y
CONFIG_VIDEO=y
CONFIG_VIDEO_LOG_LEVEL_WRN=y
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not necessary here ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, removed to let the default log level apply.

Copy link
Collaborator

@kartben kartben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very neat -- please check my comments, hopefully all pretty straightforward. Thanks!

@josuah
Copy link
Collaborator Author

josuah commented Jun 26, 2025

force-push:

Introduce a new USB Video Class (UVC) implementation from scratch.
It exposes a native Zephyr Video driver interface, allowing to call the
video_enqueue()/video_dequeue() interface. It will query the attached
video device to learn about the video capabilities, and use this to
configure the USB descriptors. At runtime, this UVC implementation will
send this device all the control requests, which it will send to the
attached video device. The application can poll the format currently
selected by the host, but will not be alerted when the host configures
a new format, as there is no video.h API for it yet.

Signed-off-by: Josuah Demangeon <me@josuah.net>
@josuah josuah force-pushed the pr-usb-uvc branch 2 times, most recently from b860551 to 35a9324 Compare June 26, 2025 20:52
@@ -0,0 +1,183 @@
.. zephyr:code-sample:: uvc
:name: USB Video webcam
:relevant-api: usbd_api video_interface
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to fix now (I mean it!) but in case there is another round of updates, just realized we now have a proper doxygen group for the UVC device api

Suggested change
:relevant-api: usbd_api video_interface
:relevant-api: usbd_api usbd_uvc video_interface

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I will aggregate all the non-blocking fixes to this branch then...
https://github.com/tinyvision-ai-inc/zephyr/pull/new/pr_fix_uvc

kartben
kartben previously approved these changes Jun 26, 2025
@josuah
Copy link
Collaborator Author

josuah commented Jun 26, 2025

We still have all the non-video boards working without problem. For instance:

west build -b rpi_pico --snippet video-sw-generator samples/subsys/usb/uvc/

video

west build -b nrf52840dongle --snippet video-sw-generator samples/subsys/usb/uvc/ -- \
  -DCONFIG_USBD_DEVICE_STACK=n -DCONFIG_USBD_DEVICE_STACK_NEXT=y # I need to get a real nrf52840dk!

video

west build -b frdm_mcxn947/mcxn947/cpu0 --snippet video-sw-generator samples/subsys/usb/uvc/

video

@jfischer-no
Copy link
Collaborator

@josuah The logging settings that were removed here should be brought back. I am also confused why they were removed?

Following the addition of USB Video Class, this adds a sample that makes
use of the zephyr,camera chosen node of any board to stream the video
source to the host. A snippet video-sw-generator can be used to test
and debug devices without a zephyr,camera chosen node.

Signed-off-by: Josuah Demangeon <me@josuah.net>
@josuah
Copy link
Collaborator Author

josuah commented Jun 27, 2025

@josuah The logging settings that were removed here should be brought back. I am also confused why they were removed?

I assumed the default log level was WRN and that the configuration was redundant, but no it is INF so removing this changed the behavior. I added them back like asked here.

Copy link

Copy link
Collaborator

@jfischer-no jfischer-no left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josuah Thank you very much. This is a significant and valuable contribution to the USB device subsystem. Thank you also for your patience.

@kartben kartben merged commit b60609a into zephyrproject-rtos:main Jun 27, 2025
31 checks passed
@josuah
Copy link
Collaborator Author

josuah commented Jun 27, 2025

👍

The time spent waiting allowed to introduce UVC directly on top of the latest video and USB APIs, and testing it plenty.

More on the roadmap! #76798 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Build System area: Devicetree Binding PR modifies or adds a Device Tree binding area: Devicetree area: Samples Samples area: USB Universal Serial Bus area: Video Video subsystem Experimental Experimental features not enabled by default platform: STM32 ST Micro STM32
Projects
None yet
Development

Successfully merging this pull request may close these issues.